package org.eden.karb.common.util;

import javax.sound.sampled.AudioFormat;

/**
 * Utility class to handle audio data.
 */
public class AudioUtils {

    public static AudioFormat getDefaultAudioFormat() {
        float sampleRate = 8000.0F;
        //8000,11025,16000,22050,44100
        int sampleSizeInBits = 8;
        //8,16
        int channels = 1;
        //1,2
        boolean signed = true;
        //true,false
        boolean bigEndian = true;
        //true,false
        return new AudioFormat(
                sampleRate,
                sampleSizeInBits,
                channels,
                signed,
                bigEndian);
    }

    /**
     * Calculate the level of the audio.
     * {@docRoot http://forums.sun.com/thread.jspa?threadID=5433582}
     *
     * @param audioData audio stream
     * @return output level
     */
    public static int calculateRMSLevel(byte[] audioData) {
        // audioData might be buffered data read from a data line
        long lSum = 0;
        for (byte anAudioData : audioData) {
            lSum = lSum + anAudioData;
        }

        double dAvg = lSum / audioData.length;

        double sumMeanSquare = 0d;
        for (byte anAudioData : audioData) {
            sumMeanSquare = sumMeanSquare + Math.pow(anAudioData - dAvg, 2d);
        }

        double averageMeanSquare = sumMeanSquare / audioData.length;
        return (int) (Math.pow(averageMeanSquare, 0.5d) + 0.5);
    }

    /**
     * Converts a array on integers that represents a sample of audio into a byte array.
     *
     * @param audioLevels audio levels sample
     * @return audio levels sample as an array of bytes
     */
    public static byte[] convert(int[] audioLevels) {
        int srcLength = audioLevels.length;
        byte[] dst = new byte[srcLength << 2];

        for (int i = 0; i < srcLength; i++) {
            int x = audioLevels[i];
            int j = i << 2;
            dst[j++] = (byte) ((x >>> 0) & 0xff);
            dst[j++] = (byte) ((x >>> 8) & 0xff);
            dst[j++] = (byte) ((x >>> 16) & 0xff);
            dst[j++] = (byte) ((x >>> 24) & 0xff);
        }
        return dst;
    }

    /**
     * Converts a array on bytes that represents a sample of audio into a integer array.
     *
     * @param src audio levels sample
     * @return audio levels sample as an array of integers
     */
    public static int[] convert(byte[] src) {
        int dstLength = src.length >>> 2;
        int[] dst = new int[dstLength];

        for (int i = 0; i < dstLength; i++) {
            int j = i << 2;
            int x = 0;
            x += (src[j++] & 0xff) << 0;
            x += (src[j++] & 0xff) << 8;
            x += (src[j++] & 0xff) << 16;
            x += (src[j++] & 0xff) << 24;
            dst[i] = x;
        }
        return dst;
    }

    public static void printStream(int[] audioLevels) {

        for (int audioLevel : audioLevels) {
            StringBuffer buffer = new StringBuffer();
            for (int i = 0; i < audioLevel; i++) {
                buffer.append("|");
            }
            System.out.println(buffer.toString());
        }
    }
}
